package com.hrvsr.downloader;

import java.io.Closeable;
import java.io.IOException;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hrvsr.common.Request;
import com.hrvsr.common.Response;
import com.hrvsr.common.consts.Consts;
import com.hrvsr.session.Session;

/**
 * closable downloader decorator, make sure to return a non-null response and
 * the request visited count increases
 */
public class ClosableSafeDownloader implements Downloader, Closeable {
	private static Logger logger = LoggerFactory.getLogger(ClosableSafeDownloader.class);
	
	private Downloader downloader;

	public ClosableSafeDownloader(final Downloader downloader) {
		this.downloader = downloader;
	}

	@Override
	public Response download(final Request request, final Session session) {
		try {
			return downloader.download(request, session);
		} catch (Exception e) {
			logger.error("error downloading {}", request, e);
			return genErrorResponse(request, session, e);
		} finally {
			visited(request, session);
		}
	}

	private Response genErrorResponse(Request request, Session session, Exception e) {
		if (session != null) {
			request.putExtraInfo(Consts.SESSION_SNAPSHOT, session.toString());
		}
		return new SafeDownloaderDefaultResponse(request, e);
	}

	private void visited(Request request, Session session) {
		Object o = request.getExtraInfo(Consts.VISITED_TIMES);
		if (o == null) {
			request.putExtraInfo(Consts.VISITED_TIMES, 1);
		} else {
			int n = (int) o;
			request.putExtraInfo(Consts.VISITED_TIMES, ++n);
		}
		if (session != null)
			request.putExtraInfo(Consts.SESSION_SNAPSHOT, session.toString());
	}

	@Override
	public void close() throws IOException {
		if (downloader instanceof Closeable) {
			IOUtils.closeQuietly((Closeable) downloader);
		}
	}

	public static Downloader adapt(final Downloader downloader) {
		if (downloader instanceof ClosableSafeDownloader) {
			return downloader;
		}
		return new ClosableSafeDownloader(downloader);
	}

	private static class SafeDownloaderDefaultResponse implements Response {
		private Request request;
	
		public SafeDownloaderDefaultResponse(Request request, Exception e) {
			this.request = request;
			request.putExtraInfo(Consts.DOWN_LOAD_ERR, e.getMessage());
		}
	
		@Override
		public Request getRequest() {
			return request;
		}
	
		@Override
		public int getStatusCode() {
			return -1;
		}
	
		@Override
		public String getContentType() {
			return null;
		}
	
		@Override
		public byte[] getContent() {
			return null;
		}
	
	}
}
